package cc.cix.hq.org.service.impl;

import cc.cix.hq.common.core.client.IUserClient;
import cc.cix.hq.common.core.entity.QueryRequest;
import cc.cix.hq.common.core.entity.org.*;
import cc.cix.hq.common.core.exception.HqException;
import cc.cix.hq.common.core.utils.HqUtil;
import cc.cix.hq.common.core.utils.SortUtil;
import cc.cix.hq.org.mapper.UserMapper;
import cc.cix.hq.org.service.*;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author cix
 */
@Service
@org.apache.dubbo.config.annotation.Service(interfaceClass = IUserClient.class)
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, IUserClient {

    private final IUserRoleService userRoleService;
    private final IDeptService deptService;
    private final PasswordEncoder passwordEncoder;
    private final IUserDataPermissionService userDataPermissionService;
    private final IRoleService roleService;

    @Override
    public cc.cix.hq.common.core.entity.Page<User> listUser(User user, QueryRequest request) {
        QueryWrapper<User> wrapper = new QueryWrapper<>(user)
                .inSql(ObjectUtil.isNotNull(user.getDeptName()), "dept_id",
                        "SELECT id FROM t_dept WHERE dept_name = " + user.getDeptName());
        SortUtil.handleWrapperSort(request, wrapper);

        IPage<User> page = page(new Page<>(request.getPageNum(), request.getPageSize()), wrapper);
        page.getRecords().forEach(i -> {
            Dept dept = deptService.lambdaQuery().eq(Dept::getId, i.getDeptId()).one();
            i.setDeptName(Optional.ofNullable(dept).map(Dept::getDeptName).orElse("无"));

            // 获取部门数据权限列表
            List<UserDataPermission> userDataPermissions = userDataPermissionService.lambdaQuery()
                    .eq(UserDataPermission::getUserId, i.getId())
                    .list();
            List<Long> deptIds = userDataPermissions.stream()
                    .map(UserDataPermission::getDeptId)
                    .collect(Collectors.toList());
            i.setDeptIds(deptIds);

            // 获取角色列表
            List<UserRole> userRoles = userRoleService.lambdaQuery().eq(UserRole::getUserId, i.getId()).list();
            List<Long> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            Role role = roleService.query()
                    .select("GROUP_CONCAT(role_name) roleName")
                    .in("id", roleIds)
                    .one();

            i.setRoleIds(roleIds);
            i.setRoleName(role.getRoleName());
        });

        return HqUtil.getPage(page);
    }

    @Override
    public User getUserByMobile(String mobile) {
        return lambdaQuery().eq(User::getMobile, mobile).one();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) throws HqException {
        // 创建用户
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        save(user);

        // 保存用户角色
        setUserRoles(user, user.getRoleIds());

        // 保存用户数据权限关联关系
        setUserDataPermissions(user, user.getDeptIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        // 如果存在密码
        if (user.getPassword() != null) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }

        // 更新用户
        user.setMobile(null);
        user.setCreateTime(null);
        updateById(user);

        userRoleService.lambdaUpdate().eq(UserRole::getUserId, user.getId()).remove();
        setUserRoles(user, user.getRoleIds());

        userDataPermissionService.lambdaUpdate().eq(UserDataPermission::getUserId, user.getId()).remove();
        setUserDataPermissions(user, user.getDeptIds());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByIds(List<String> userIds) {
        removeByIds(userIds);

        // 删除用户角色
        userRoleService.lambdaUpdate().in(UserRole::getUserId, userIds).remove();
        userDataPermissionService.lambdaUpdate().in(UserDataPermission::getUserId, userIds).remove();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProfile(User user) throws HqException {
        // 如果存在密码
        if (user.getPassword() != null) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }

        if (isCurrentUser(user.getId())) {
            updateById(user);
        } else {
            throw new HqException("您无权修改别人的账号信息！");
        }
    }

    @SneakyThrows
    @Override
    public void registerUser(User user) {
        // 默认设置
        List<Long> roleIds = roleService.lambdaQuery().eq(Role::getRoleName, "普通用户").list().stream()
                .map(Role::getId)
                .collect(Collectors.toList());

        user.setStatus(User.STATUS_VALID);
        user.setRoleIds(roleIds);
        user.setSex(User.SEX_FEMALE);
        user.setUsername(user.getMobile());

        // 创建用户
        createUser(user);
    }

    private void setUserRoles(User user, List<Long> roleIds) {
        if (roleIds == null || roleIds.isEmpty()) {
            return;
        }

        List<UserRole> userRoles = new ArrayList<>();
        roleIds.forEach(i -> {
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(i);
            userRoles.add(userRole);
        });
        userRoleService.saveBatch(userRoles);
    }

    private void setUserDataPermissions(User user, List<Long> deptIds) {
        if (deptIds == null || deptIds.isEmpty()) {
            return;
        }

        List<UserDataPermission> userDataPermissions = new ArrayList<>();
        deptIds.forEach(i -> {
            UserDataPermission permission = new UserDataPermission();
            permission.setDeptId(i);
            permission.setUserId(user.getId());
            userDataPermissions.add(permission);
        });
        userDataPermissionService.saveBatch(userDataPermissions);
    }

    private boolean isCurrentUser(Long id) {
        return Optional.ofNullable(HqUtil.getCurrentUser()).map(i -> ObjectUtil.equals(id, i.getId())).orElse(false);
    }

}
